<template>
  <div class="hls-player-wrapper" :style="{ width, height }">
    <!-- 播放器容器 -->
    <div class="player-container">
      <!-- 加载状态 -->
      <div v-if="isLoading && !hasError" class="loading-overlay">
        <div class="spinner"></div>
        <p class="loading-text">{{ loadingText }}</p>
      </div>

      <!-- 错误状态 -->
      <div v-if="hasError" class="error-overlay">
        <div class="error-icon">
          <i class="fas fa-exclamation-triangle"></i>
        </div>
        <p class="error-message">{{ errorMessage }}</p>
        <button
          class="retry-button"
          @click="reloadPlayer"
        >
          重新加载
        </button>
      </div>

      <!-- 视频播放器 -->
      <video
        ref="videoRef"
        class="video-player"
        :autoplay="autoplay"
        :muted="muted"
        :loop="loop"
        :playsinline="playsinline"
        @timeupdate="handleTimeUpdate"
        @play="handlePlay"
        @pause="handlePause"
        @ended="handleEnded"
        @error="handleVideoError"
      ></video>

      <!-- 自定义控制栏 (可选) -->
      <div v-if="showControls" class="custom-controls" :class="{ 'controls-hidden': !isControlsVisible }">
        <div class="progress-bar" @click="seek">
          <div
            class="progress-filled"
            :style="{ width: `${progressPercent}%` }"
          ></div>
        </div>
        <div class="controls-buttons">
          <button @click="togglePlay" class="control-button">
            <i class="fas" :class="isPlaying ? 'fa-pause' : 'fa-play'"></i>
          </button>
          <button @click="toggleMute" class="control-button">
            <i class="fas" :class="muted ? 'fa-volume-mute' : 'fa-volume-up'"></i>
          </button>
          <div class="volume-control">
            <input
              type="range"
              min="0"
              max="1"
              step="0.1"
              v-model="volume"
              @input="handleVolumeChange"
            >
          </div>
          <span class="time-display">
            {{ formatTime(currentTime) }} / {{ formatTime(duration) }}
          </span>
          <button @click="toggleFullscreen" class="control-button">
            <i class="fas fa-expand"></i>
          </button>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import Hls from 'hls.js';

export default {
  name: 'HlsPlayer',
  props: {
    // 视频源地址 (m3u8)
    src: {
      type: String,
      required: true,
      default: ''
    },

    // 播放器宽度
    width: {
      type: [String, Number],
      default: '50px'
    },

    // 播放器高度
    height: {
      type: [String, Number],
      default: '500px'
    },

    // 是否自动播放
    autoplay: {
      type: Boolean,
      default: false
    },

    // 是否静音
    muted: {
      type: Boolean,
      default: false
    },

    // 是否循环播放
    loop: {
      type: Boolean,
      default: false
    },

    // 是否在移动设备上内联播放
    playsinline: {
      type: Boolean,
      default: true
    },

    // 是否显示自定义控制栏
    showControls: {
      type: Boolean,
      default: true
    },

    // 加载提示文本
    loadingText: {
      type: String,
      default: '正在加载视频...'
    }
  },

  data() {
    return {
      // 播放器实例
      video: null,
      hls: null,

      // 播放状态
      isLoading: true,
      isPlaying: false,
      currentTime: 0,
      duration: 0,
      volume: 1,
      progressPercent: 0,

      // 错误状态
      hasError: false,
      errorMessage: '视频加载失败，请稍后重试',

      // 控制栏显示状态
      isControlsVisible: true,
      controlsTimer: null
    };
  },

  watch: {
    // 监听视频源变化，重新加载
    src(newVal, oldVal) {
      if (newVal && newVal !== oldVal) {
        this.reloadPlayer();
      }
    },

    // 监听静音状态变化
    muted(newVal) {
      if (this.video) {
        this.video.muted = newVal;
      }
    }
  },

  mounted() {
    this.initPlayer();
    this.setupControlsVisibility();
  },

  beforeUnmount() {
    this.destroyPlayer();
  },

  methods: {
    // 初始化播放器
    initPlayer() {
      this.video = this.$refs.videoRef;
      if (!this.video) return;

      // 重置状态
      this.isLoading = true;
      this.hasError = false;

      // 设置初始音量
      this.video.volume = this.volume;

      // 处理HLS流
      this.setupHls();
    },

    // 设置HLS
    setupHls() {
      if (!this.src) {
        this.handleError('未提供视频源地址');
        return;
      }

      // 检查浏览器是否原生支持HLS
      if (this.video.canPlayType('application/vnd.apple.mpegurl')) {
        // Safari等原生支持HLS的浏览器
        this.video.src = this.src;
        this.video.addEventListener('loadedmetadata', this.handleLoadedMetadata);
        // if (this.autoplay) {
        //   this.video.play().catch(err => this.handleError('自动播放被浏览器阻止，请手动播放'));
        // }
      }
      // 检查是否可以使用hls.js
      else if (Hls.isSupported()) {
        // 销毁可能存在的旧实例
        if (this.hls) {
          this.hls.destroy();
        }

        // 创建新的hls实例
        this.hls = new Hls({
          maxBufferLength: 30,
          maxMaxBufferLength: 600,
          startLevel: -1 // 自动选择适合带宽的级别
        });

        // 加载视频源
        this.hls.loadSource(this.src);
        this.hls.attachMedia(this.video);

        // 监听hls事件
        this.hls.on(Hls.Events.MANIFEST_PARSED, () => {
          this.handleLoadedMetadata();
          // if (this.autoplay) {
          //   this.video.play().catch(err => this.handleError('自动播放被浏览器阻止，请手动播放'));
          // }
        });

        // 监听错误事件
        this.hls.on(Hls.Events.ERROR, (event, data) => {
          console.error('HLS错误:', data);
          this.handleHlsError(data);
        });
      }
      // 不支持HLS
      else {
        this.handleError('您的浏览器不支持HLS视频流播放');
      }
    },

    // 处理视频元数据加载完成
    handleLoadedMetadata() {
      this.isLoading = false;
      this.duration = this.video.duration || 0;
      this.$emit('loaded', { duration: this.duration });
    },

    // 处理HLS错误
    handleHlsError(data) {
      this.isLoading = false;
      this.hasError = true;

      // 致命错误处理
      if (data.fatal) {
        switch(data.type) {
          case Hls.ErrorTypes.NETWORK_ERROR:
            this.errorMessage = '网络错误，无法加载视频';
            // 尝试重新加载
            this.hls.startLoad();
            break;
          case Hls.ErrorTypes.MEDIA_ERROR:
            this.errorMessage = '媒体错误，无法播放视频';
            // 尝试恢复
            this.hls.recoverMediaError();
            break;
          default:
            this.errorMessage = '视频播放出错，无法恢复';
            this.destroyPlayer();
            break;
        }
      } else {
        this.errorMessage = this.getErrorMessage(data.type) || '视频播放出错';
      }

      this.$emit('error', { type: data.type, message: this.errorMessage });
    },

    // 处理视频元素错误
    handleVideoError(event) {
      this.isLoading = false;
      this.hasError = true;

      switch(event.target.error.code) {
        case MediaError.MEDIA_ERR_ABORTED:
          this.errorMessage = '视频加载被中止';
          break;
        case MediaError.MEDIA_ERR_NETWORK:
          this.errorMessage = '网络错误导致视频加载失败';
          break;
        case MediaError.MEDIA_ERR_DECODE:
          this.errorMessage = '视频解码失败';
          break;
        case MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED:
          this.errorMessage = '视频格式不支持';
          break;
        default:
          this.errorMessage = '视频播放出错';
      }

      this.$emit('error', { code: event.target.error.code, message: this.errorMessage });
    },

    // 通用错误处理
    handleError(message) {
      this.isLoading = false;
      this.hasError = true;
      this.errorMessage = message;
      this.$emit('error', { message });
    },

    // 重新加载播放器
    reloadPlayer() {
      this.destroyPlayer();
      this.initPlayer();
      this.$emit('reload');
    },

    // 销毁播放器
    destroyPlayer() {
      if (this.hls) {
        this.hls.destroy();
        this.hls = null;
      }

      if (this.video) {
        this.video.removeEventListener('loadedmetadata', this.handleLoadedMetadata);
        this.video.pause();
        this.video.src = '';
        this.video = null;
      }

      // 清除计时器
      if (this.controlsTimer) {
        clearTimeout(this.controlsTimer);
        this.controlsTimer = null;
      }
    },

    // 切换播放/暂停
    togglePlay() {
      if (!this.video) return;

      if (this.video.paused) {
        this.video.play().catch(err => {
          this.handleError('播放被浏览器阻止，请尝试手动点击播放');
        });
      } else {
        this.video.pause();
      }
    },

    // 处理播放事件
    handlePlay() {
      this.isPlaying = true;
      this.$emit('play');
    },

    // 处理暂停事件
    handlePause() {
      this.isPlaying = false;
      this.$emit('pause');
    },

    // 处理播放结束事件
    handleEnded() {
      this.isPlaying = false;
      this.$emit('ended');
    },

    // 处理时间更新
    handleTimeUpdate() {
      if (!this.video) return;

      this.currentTime = this.video.currentTime;
      this.duration = this.video.duration || 0;
      this.progressPercent = this.duration ? (this.currentTime / this.duration) * 100 : 0;

      this.$emit('timeupdate', {
        currentTime: this.currentTime,
        duration: this.duration,
        progress: this.progressPercent
      });

      // 控制栏自动隐藏
      this.hideControlsAfterDelay();
    },

    // 切换静音
    toggleMute() {
      if (!this.video) return;

      this.muted = !this.muted;
      this.video.muted = this.muted;
      this.$emit('volumechange', { muted: this.muted, volume: this.video.volume });
    },

    // 处理音量变化
    handleVolumeChange() {
      if (!this.video) return;

      this.video.volume = this.volume;
      this.muted = this.volume === 0;
      this.$emit('volumechange', { muted: this.muted, volume: this.volume });
    },

    // 进度条点击跳转
    seek(event) {
      if (!this.video || !this.duration) return;

      const rect = event.currentTarget.getBoundingClientRect();
      const pos = (event.clientX - rect.left) / rect.width;
      const newTime = pos * this.duration;

      this.video.currentTime = newTime;
      this.currentTime = newTime;
      this.progressPercent = pos * 100;
    },

    // 切换全屏
    toggleFullscreen() {
      const container = this.$el.querySelector('.player-container');

      if (!document.fullscreenElement) {
        container.requestFullscreen().catch(err => {
          console.error(`全屏切换错误: ${err.message}`);
        });
      } else {
        if (document.exitFullscreen) {
          document.exitFullscreen();
        }
      }
    },

    // 格式化时间 (秒 -> MM:SS)
    formatTime(seconds) {
      if (isNaN(seconds)) return '00:00';

      const minutes = Math.floor(seconds / 60);
      const secs = Math.floor(seconds % 60);

      return `${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
    },

    // 设置控制栏显示/隐藏逻辑
    setupControlsVisibility() {
      const container = this.$el.querySelector('.player-container');

      // 鼠标移动时显示控制栏
      container.addEventListener('mousemove', () => {
        this.isControlsVisible = true;
        this.hideControlsAfterDelay();
      });

      // 点击播放器切换播放状态
      container.addEventListener('click', (event) => {
        // 避免点击控制元素时触发
        if (!event.target.closest('.custom-controls')) {
          this.togglePlay();
        }
      });
    },

    // 延迟隐藏控制栏
    hideControlsAfterDelay() {
      if (this.controlsTimer) {
        clearTimeout(this.controlsTimer);
      }

      // 播放状态下才自动隐藏
      if (this.isPlaying) {
        this.controlsTimer = setTimeout(() => {
          this.isControlsVisible = false;
        }, 3000);
      }
    },

    // 根据错误类型获取错误信息
    getErrorMessage(errorType) {
      const errorMap = {
        [Hls.ErrorTypes.NETWORK_ERROR]: '网络错误',
        [Hls.ErrorTypes.MEDIA_ERROR]: '媒体错误',
        [Hls.ErrorTypes.KEY_SYSTEM_ERROR]: '加密内容解密错误',
        [Hls.ErrorTypes.MANIFEST_ERROR]: '视频清单解析错误'
      };

      return errorMap[errorType];
    }
  }
};
</script>

<style scoped>
.hls-player-wrapper {
  position: relative;
  display: inline-block;
  background-color: #000;
}

.player-container {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.video-player {
  width: 100%;
  height: 100%;
  object-fit: contain;
  background-color: #000;
}

/* 加载状态 */
.loading-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  background-color: rgba(0, 0, 0, 0.7);
  color: #fff;
  z-index: 10;
}

.spinner {
  width: 40px;
  height: 40px;
  border: 4px solid rgba(255, 255, 255, 0.3);
  border-radius: 50%;
  border-top-color: #fff;
  animation: spin 1s ease-in-out infinite;
  margin-bottom: 16px;
}

.loading-text {
  font-size: 16px;
  font-weight: 500;
}

/* 错误状态 */
.error-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  background-color: rgba(0, 0, 0, 0.8);
  color: #fff;
  z-index: 10;
  padding: 20px;
  text-align: center;
}

.error-icon {
  font-size: 48px;
  color: #ffcc00;
  margin-bottom: 16px;
}

.error-message {
  font-size: 16px;
  margin-bottom: 24px;
  max-width: 80%;
}

.retry-button {
  padding: 10px 20px;
  background-color: #42b983;
  color: #fff;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  transition: background-color 0.3s;
}

.retry-button:hover {
  background-color: #359e6d;
}

/* 自定义控制栏 */
.custom-controls {
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent);
  color: #fff;
  padding: 20px 10px 10px;
  transition: opacity 0.3s;
  z-index: 5;
}

.controls-hidden {
  opacity: 0;
  pointer-events: none;
}

.progress-bar {
  width: 100%;
  height: 4px;
  background-color: rgba(255, 255, 255, 0.3);
  border-radius: 2px;
  cursor: pointer;
  margin-bottom: 10px;
}

.progress-filled {
  height: 100%;
  background-color: #42b983;
  border-radius: 2px;
  transition: width 0.1s;
}

.controls-buttons {
  display: flex;
  align-items: center;
  gap: 10px;
}

.control-button {
  background: none;
  border: none;
  color: #fff;
  cursor: pointer;
  font-size: 16px;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background-color 0.2s;
}

.control-button:hover {
  background-color: rgba(255, 255, 255, 0.2);
}

.volume-control input {
  width: 80px;
  cursor: pointer;
}

.time-display {
  font-size: 14px;
  margin-left: auto;
  color: rgba(255, 255, 255, 0.9);
}

@keyframes spin {
  to { transform: rotate(360deg); }
}
</style>
